/*
录音 Recorder扩展，动态波形显示
https://github.com/xiangyuecn/Recorder
*/
(function(){

    var WaveView=function(set){
        return new fn(set);
    };
    var ViewTxt="WaveView";
    var fn=function(set){
        var This=this;
        var o={
            /*
            elem:"css selector" //自动显示到dom，并以此dom大小为显示大小
                //或者配置显示大小，手动把waveviewObj.elem显示到别的地方
            ,width:0 //显示宽度
            ,height:0 //显示高度
            
            以上配置二选一
            */
            
            scale:2 //缩放系数，应为正整数，使用2(3? no!)倍宽高进行绘制，避免移动端绘制模糊
            ,speed:9 //移动速度系数，越大越快
            ,phase:21.8 //相位，调整了速度后，调整这个值得到一个看起来舒服的波形
            
            ,fps:20 //绘制帧率，调整后也需调整phase值
            ,keep:true //当停止了input输入时，是否保持波形，设为false停止后将变成一条线
            
            ,lineWidth:3 //线条基础粗细
            
            //渐变色配置：[位置，css颜色，...] 位置: 取值0.0-1.0之间
            ,linear1:[0,"rgba(150,96,238,1)",0.2,"rgba(170,79,249,1)",1,"rgba(53,199,253,1)"] //线条渐变色1，从左到右
            ,linear2:[0,"rgba(209,130,255,0.6)",1,"rgba(53,199,255,0.6)"] //线条渐变色2，从左到右
            ,linearBg:[0,"rgba(255,255,255,0.2)",1,"rgba(54,197,252,0.2)"] //背景渐变色，从上到下
        };
        for(var k in set){
            o[k]=set[k];
        };
        This.set=set=o;
        
        var elem=set.elem;
        if(elem){
            if(typeof(elem)=="string"){
                elem=document.querySelector(elem);
            }else if(elem.length){
                elem=elem[0];
            };
        };
        if(elem){
            set.width=elem.offsetWidth;
            set.height=elem.offsetHeight;
        };
        
        var scale=set.scale;
        var width=set.width*scale;
        var height=set.height*scale;
        if(!width || !height){
            throw new Error(ViewTxt+"无宽高");
        }
        
        var thisElem=This.elem=document.createElement("div");
        var lowerCss=["","transform-origin:0 0;","transform:scale("+(1/scale)+");"];
        thisElem.innerHTML='<div style="width:'+set.width+'px;height:'+set.height+'px;overflow:hidden"><div style="width:'+width+'px;height:'+height+'px;'+lowerCss.join("-webkit-")+lowerCss.join("-ms-")+lowerCss.join("-moz-")+lowerCss.join("")+'"><canvas/></div></div>';
        
        var canvas=This.canvas=thisElem.querySelector("canvas");
        var ctx=This.ctx=canvas.getContext("2d");
        canvas.width=width;
        canvas.height=height;
        
        This.linear1=This.genLinear(ctx,width,set.linear1);
        This.linear2=This.genLinear(ctx,width,set.linear2);
        This.linearBg=This.genLinear(ctx,height,set.linearBg,true);
        
        if(elem){
            elem.innerHTML="";
            elem.appendChild(thisElem);
        };
        
        This._phase=0;
    };
    fn.prototype=WaveView.prototype={
        genLinear:function(ctx,size,colors,top){
            var rtv=ctx.createLinearGradient(0,0,top?0:size,top?size:0);
            for(var i=0;i<colors.length;){
                rtv.addColorStop(colors[i++],colors[i++]);
            };
            return rtv;
        }
        ,genPath:function(frequency,amplitude,phase){
            //曲线生成算法参考 https://github.com/HaloMartin/MCVoiceWave/blob/f6dc28975fbe0f7fc6cc4dbc2e61b0aa5574e9bc/MCVoiceWave/MCVoiceWaveView.m#L268
            var rtv=[];
            var This=this,set=This.set;
            var scale=set.scale;
            var width=set.width*scale;
            var maxAmplitude=set.height*scale/2;
            
            for(var x=0;x<width;x+=scale) {
                var scaling=(1+Math.cos(Math.PI+(x/width)*2*Math.PI))/2;
                var y=scaling*maxAmplitude*amplitude*Math.sin(2*Math.PI*(x/width)*frequency+phase)+maxAmplitude;
                rtv.push(y);
            }
            return rtv;
        }
        ,input:function(pcmData,powerLevel,sampleRate){
            var This=this;
            This.sampleRate=sampleRate;
            This.pcmData=pcmData;
            This.pcmPos=0;
            
            This.inputTime=Date.now();
            This.schedule();
        }
        ,schedule:function(){
            var This=this,set=This.set;
            var interval=Math.floor(1000/set.fps);
            if(!This.timer){
                This.timer=setInterval(function(){
                    This.schedule();
                },interval);
            };
            
            var now=Date.now();
            var drawTime=This.drawTime||0;
            if(now-drawTime<interval){
                //没到间隔时间，不绘制
                return;
            };
            This.drawTime=now;
            
            //切分当前需要的绘制数据
            var bufferSize=This.sampleRate/set.fps;
            var pcm=This.pcmData;
            var pos=This.pcmPos;
            var len=Math.max(0, Math.min(bufferSize,pcm.length-pos));
            var sum=0;
            for(var i=0;i<len;i++,pos++){
                sum+=Math.abs(pcm[pos]);
            };
            This.pcmPos=pos;
            
            //推入绘制
            if(len || !set.keep){
                This.draw(Recorder.PowerLevel(sum, len));
            }
            if(!len && now-This.inputTime>1300){
                //超时没有输入，干掉定时器
                clearInterval(This.timer);
                This.timer=0;
            }
        }
        ,draw:function(powerLevel){
            var This=this,set=This.set;
            var ctx=This.ctx;
            var scale=set.scale;
            var width=set.width*scale;
            var height=set.height*scale;
            
            var speedx=set.speed/set.fps;
            var phase=This._phase-=speedx;//位移速度
            var phase2=phase+speedx*set.phase;
            var amplitude=powerLevel/100;
            var path1=This.genPath(2,amplitude,phase);
            var path2=This.genPath(1.8,amplitude,phase2);
            
            //开始绘制图形
            ctx.clearRect(0,0,width,height);
            
            //绘制包围背景
            ctx.beginPath();
            for(var i=0,x=0;x<width;i++,x+=scale) {
                if (x==0) {
                    ctx.moveTo(x,path1[i]);
                }else {
                    ctx.lineTo(x,path1[i]);
                };
            };
            i--;
            for(var x=width-1;x>=0;i--,x-=scale) {
                ctx.lineTo(x,path2[i]);
            };
            ctx.closePath();
            ctx.fillStyle=This.linearBg;
            ctx.fill();
            
            //绘制线
            This.drawPath(path2,This.linear2);
            This.drawPath(path1,This.linear1);
        }
        ,drawPath:function(path,linear){
            var This=this,set=This.set;
            var ctx=This.ctx;
            var scale=set.scale;
            var width=set.width*scale;
            
            ctx.beginPath();
            for(var i=0,x=0;x<width;i++,x+=scale) {
                if (x==0) {
                    ctx.moveTo(x,path[i]);
                }else {
                    ctx.lineTo(x,path[i]);
                };
            };
            ctx.lineWidth=set.lineWidth*scale;
            ctx.strokeStyle=linear;
            ctx.stroke();
        }
    };
    Recorder[ViewTxt]=WaveView;
    
        
    })();